/**
 * @file    tiny_vec.h
 * @author  Ying-Po Liao <lrobin@neo.tamu.edu>
 * @version 1.0
 *
 * @section This file is the header file for tiny_vector
 *
 * CSCE-689 Design Using C++
 * Final Project
 */
#ifndef TINY_VECTOR_H
#define TINY_VECTOR_H

/**
 *  @brief      tiny vector. A numeric vector with fixed length elements
 *  @tparam     T Numeric Type
 *  @tparam     N Number of elements
 */
template <typename T, unsigned int N>
class tiny_vector
{
public:
	typedef T		num_type;
	typedef T*		iterator;
	typedef const T*	const_iterator;
	
	static constexpr unsigned int num_elements = N;
	
	tiny_vector() {}
	~tiny_vector() {}
	
	tiny_vector( const tiny_vector<T, N>& vec );	//!< copy constructor
	tiny_vector( tiny_vector<T, N>&& vec );		//!< move constructor
	
	/**
	 *  @brief	initializer_list.
	 *		
	 *  tiny_vector can be initialized by a list of numbers. i.e.,
	 *  tiny_vector<double, 3> a = {1.2, 3.3, 4.2};
	 */	
	tiny_vector( std::initializer_list<T> list );
	tiny_vector( const T init_num );
	tiny_vector( const T init_arr[] );
	
	template <typename T2>	
	tiny_vector( const tiny_vector<T2, N>& vec );
	
	num_type& 	operator[] ( unsigned int i );
	const num_type&	operator[] ( unsigned int i ) const;

	num_type& 	operator() ( unsigned int i );
	const num_type&	operator() ( unsigned int i ) const;
		
	iterator	begin() 	{ return data; }
	const_iterator	begin() const	{ return data; }
	iterator	end()		{ return data + num_elements; }
	const_iterator	end()	const	{ return data + num_elements; }

	tiny_vector& operator= ( const T const_val );
	tiny_vector& operator+=( const T const_val );
	tiny_vector& operator-=( const T const_val );
	tiny_vector& operator*=( const T const_val );
	tiny_vector& operator/=( const T const_val );
	tiny_vector& operator%=( const T const_val );
	tiny_vector& operator^=( const T const_val );
	tiny_vector& operator&=( const T const_val );
	tiny_vector& operator|=( const T const_val );
	tiny_vector& operator>>=( const int );
	tiny_vector& operator<<=( const int );
    
	template <typename T2> tiny_vector& operator= ( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator+=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator-=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator*=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator/=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator%=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator^=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator&=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator|=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator>>=( const tiny_vector<T2, N>& vec );
	template <typename T2> tiny_vector& operator<<=( const tiny_vector<T2, N>& vec );
	
	/** [TODO] I temporarily enable == and !=, since the other
	  * operators > < >= <= possibly have implements different
	  * from element-wise comparsion, i.e., L2-norm comparasion
	  * for > or <
	  */
	bool operator==( const tiny_vector<T, N>& vec );
	bool operator!=( const tiny_vector<T, N>& vec );
	//bool operator >( const tiny_vector<T, N>& vec );
	//bool operator <( const tiny_vector<T, N>& vec );
	//bool operator>=( const tiny_vector<T, N>& vec );
	//bool operator<=( const tiny_vector<T, N>& vec );

protected:
	constexpr bool range_check( unsigned int i ) { return i < N; }
	T data[N];
};
	
#endif //!< TINY_VECTOR_H